home *** CD-ROM | disk | FTP | other *** search
- UNIT cct; {$project vt }
- { Programmierung des CCT-Chips (Computer Controlled Teletext) SAA5246 }
-
- INTERFACE; FROM vt USES global,i2c_serial;
-
- VAR aktspeicher: Integer; { der Speicher, in dem die VT-Uhr läuft }
-
- PROCEDURE display_select(speicher: Byte);
- PROCEDURE TV_display(mode: Byte);
- FUNCTION VTstat: Byte;
- PROCEDURE sperren(speicher: Byte);
- PROCEDURE anfordern(speicher: Byte; page, subpage: Integer; mask: Byte);
- PROCEDURE init_CCT;
- FUNCTION seite_da(speicher: Byte): Boolean;
- PROCEDURE gettime(speicher: Byte; VAR zeit: Str80);
- PROCEDURE gethead(speicher: Byte; VAR head: Str80);
- PROCEDURE getpage(speicher: Byte; seite: p_onepage; ganz: Boolean);
-
- { ---------------------------------------------------------------------- }
-
- IMPLEMENTATION;
-
- {$opt q,s+,i+ } { keine Laufzeitprüfungen außer Stack und Feldindizes }
-
- CONST SAA5246 = $22;
- PBLF = $20;
- DOCARE = $10;
- NOTHOLD = $08;
- SERMAG = $0800; { C11 }
-
- VAR i2cdata: ARRAY[1..20] OF Byte; { kleiner Puffer für Kommandos }
-
- PROCEDURE display_select{(speicher: Byte)};
- { Einen der 8 Seitenspeicher zur Anzeige auswählen }
- BEGIN
- setregister(SAA5246,4,speicher);
- END;
-
- PROCEDURE TV_display{(mode: Byte)};
- { Art der Anzeige am Fernseher auswählen. }
- BEGIN
- i2cdata[1] := 5;
- CASE mode OF
- 2: { Normalseiten bildfüllend, Schlagzeilen als Boxen }
- BEGIN i2cdata[2] := %11001100; i2cdata[3] := %01001111; END;
- 1: { Normalseiten als Boxen, Schlagzeilen transparent }
- BEGIN i2cdata[2] := %11001111; i2cdata[3] := %00001111; END;
- OTHERWISE { Anzeige aus }
- BEGIN i2cdata[2] := %00000011; i2cdata[3] := %00000011; END;
- END;
- i2cdata[4] := %00000111;
- i2cbusIO(SAA5246,^i2cdata,4);
- END;
-
- FUNCTION VTstat{: Byte};
- { Liest aus dem CCT das Register R11B. Bedeutung: bit0 - Videosignal vorh., }
- { bit1 - Textsignal vorh., bit2-5 - ROM-Version }
- BEGIN
- setregister(SAA5246,0,%00000001); { R11B aktivieren }
- VTstat := getregister(SAA5246,11); { Status lesen }
- setregister(SAA5246,0,%00000000); { R11 aktivieren }
- END;
-
- PROCEDURE sperren{(speicher: Byte)};
- { Seitensuche eines Empfangskreises anhalten, damit nicht evtl. niederpriore }
- { Empfangskreise behindert werden. Die Sperre wird bei Programmierung einer }
- { neuen Seitenanforderung automatisch aufgehoben. }
- BEGIN
- i2cdata[1] := 2;
- i2cdata[2] := speicher*16;
- i2cdata[3] := 0;
- i2cbusIO(SAA5246,^i2cdata,3);
- END;
-
- PROCEDURE anfordern{(speicher: Byte; page, subpage: Integer; mask: Byte)};
- { Einlesen einer Seite in einen Seitenspeicher 0..7 anfordern, Unterseite nur }
- { direkt anfordern, wenn subpage > 0 }
- { <mask> ist eine dreistellige Binärzahl, wo eine '0' steht, wird in der }
- { entsprechenden Ziffer der angeforderten Seitennummer das DOCARE-Bit }
- { gelöscht. }
- VAR lauf: Integer;
- BEGIN
- { Seitenanforderung beschreiben: }
- i2cdata[1] := 2;
- i2cdata[2] := speicher*16;
- i2cdata[3] := ((page SHR 8) AND $7) OR NOTHOLD;
- i2cdata[4] := (page SHR 4) AND $F;
- i2cdata[5] := page AND $F;
- IF page > 0 THEN
- FOR lauf := 3 TO 5 DO
- IF Odd(mask SHR (5-lauf)) THEN
- i2cdata[lauf] := i2cdata[lauf] OR DOCARE;
- i2cdata[6] := (subpage SHR 12) AND $3;
- i2cdata[7] := (subpage SHR 8) AND $F;
- i2cdata[8] := (subpage SHR 4) AND $7
- i2cdata[9] := subpage AND $F;
- IF subpage > 0 THEN
- FOR lauf := 6 TO 9 DO i2cdata[lauf] := i2cdata[lauf] OR DOCARE;
- i2cbusIO(SAA5246,^i2cdata,9)
- END;
-
- PROCEDURE init_CCT;
- VAR i: Byte;
- BEGIN
- { Wichtig in R1: bit5 - ACQ OFF, Decoder-NotAus; bit2 - TCS ON, }
- { RGB-Ausgangssignal wird mit Fernsehbild synchronisiert. }
- setregister(SAA5246,1,%00000100);
- { Seitensuche sperren: }
- FOR i := 0 TO maxactive-1 DO BEGIN
- sperren(i); activejobs[i].pg := 0;
- END;
- { alle Seitenspeicher löschen: }
- FOR i := 0 TO 7 DO BEGIN
- setregister(SAA5246,8,%00001000 OR i); Delay(2);
- { Löschvorgang dauert bis zu 22 ms, darum mal jeweils 40 ms warten. }
- END;
- { R11 aktivieren }
- setregister(SAA5246,0,%00000000);
- { Fernsehdarstellung einschalten }
- display_select(0);
- TV_display(2);
- END;
-
- FUNCTION seite_da{(speicher: Byte): Boolean};
- { Überprüft, ob die für einen Speicher 0..7 angeforderte Seite bereits }
- { eingetroffen ist. Das Statusflag PBLF, das in diesem Fall gelöscht ist, }
- { muß danach wieder gesetzt werden. Das geschieht entweder implizit beim }
- { Programmieren einer neuen Seitenanforderung oder explizit durch }
- { Schreibzugriff, in diesem Programm in getpage(). }
- { Problem: das Statusflag PBLF bezieht sich auf den Empfang der Kopfzeile, }
- { nicht etwa den Empfang der kompletten Seite. Genauer gesagt: für letzteres }
- { existiert überhaupt kein Statusflag! }
- { Nun ist das nicht ganz so tragisch, nach Empfang der Kopfzeile kann man }
- { bereits bedenkenlos die Statuszeile 25 mit Steuerbits und Seitennummer }
- { lesen. Und in vielen Fällen geht es sogar gut, sofort mit dem Einlesen }
- { der gesamten Seite zu beginnen, da sich nämlich maximal 11 Seiten pro }
- { Sekunde über den I²C-Bus schaufeln lassen, während der Videotext selbst }
- { mit ca. 13 Seiten pro Sekunde einrollt: Die noch leere Seite wird }
- { schneller aufgefüllt, als sie ausgelesen werden kann. }
- { Probleme entstehen natürlich, wenn der Empfang der VT-Seite länger als }
- { ca. 1/10 s dauert. Das ist möglich, wenn der Sender nicht alle zur }
- { VT-Übertragung zulässigen Rasterzeilen ausnutzt, oder wenn er gar den }
- { Magazin-gemischten Übertragungsmodus verwendet. Letzteres ist aber an }
- { einem Statusflag (C11) vom Programm aus erkennbar, hm ... }
- BEGIN
- seite_da := False;
- { Byte 9 der Statuszeile (Zeile 25) adressieren ... }
- i2cdata[1] := 8;
- i2cdata[2] := speicher;
- i2cdata[3] := 25; i2cdata[4] := 9;
- i2cbusIO(SAA5246,^i2cdata,4);
- IF i2c_status<>0 THEN Exit;
- { ... und auslesen: }
- i2cbusIO(SAA5246,^i2cdata,-1);
- IF i2c_status<>0 THEN Exit;
- seite_da := (i2cdata[1] AND PBLF)=0;
- END;
-
- PROCEDURE gettime{(speicher: Byte; VAR zeit: Str80)};
- { liest aus einer Speicherseite 0..7 des CCT-Bausteins die Uhrzeit }
- VAR i: Integer;
- BEGIN
- zeit := ' ';
- { Uhrzeit aus der Seite im CCT lesen: Zeile 0, Spalte 32 }
- i2cdata[1] := 8;
- i2cdata[2] := speicher;
- i2cdata[3] := 0; i2cdata[4] := 32;
- i2cbusIO(SAA5246,^i2cdata,4);
- IF i2c_status<>0 THEN Exit;
- { Uhrzeit lesen: }
- i2cbusIO(SAA5246,^i2cdata,-8);
- IF i2c_status<>0 THEN Exit;
- FOR i := 1 TO 8 DO
- IF i2cdata[i] IN [32..127] THEN zeit[i] := Chr(i2cdata[i]);
- END;
-
- PROCEDURE gethead{(speicher: Byte; VAR head: Str80)};
- { liest die 24 Byte Titelzeile zwischen Statusfeld und Uhrzeit }
- VAR i: Integer;
- BEGIN
- head := '';
- { Seitenspeicher addressieren: Zeile 0, Spalte 8 }
- i2cdata[1] := 8;
- i2cdata[2] := speicher;
- i2cdata[3] := 0; i2cdata[4] := 8;
- i2cbusIO(SAA5246,^i2cdata,4);
- IF i2c_status<>0 THEN Exit;
- { Zeile lesen: }
- i2cbusIO(SAA5246,^head,-24);
- IF i2c_status<>0 THEN Exit;
- FOR i := 1 TO 24 DO
- IF NOT (Ord(head[i]) IN [32..127]) THEN head[i] := ' ';
- head[25] := #0;
- END;
-
- PROCEDURE getpage{(speicher: Byte; seite: p_onepage; ganz: Boolean)};
- { Liest eine Speicherseite (0..7) aus dem CCT-Baustein aus und speichert }
- { diese Seite im Amiga. Für <ganz>=false werden nur die Statusinformationen }
- { aus Zeile 25 gelesen. }
- { Abschließend wird das Statusflag PBLF wieder gesetzt! }
- VAR i,h: Integer;
- status: ARRAY [0..9] OF Byte;
- hex: ARRAY [0..16] OF Char;
- s: str80;
- BEGIN
- hex := '0123456789ABCDEF';
- seite^.pg := 0; seite^.sp := 0; seite^.cbits := 0;
- { Status aus der Seite im CCT lesen: Zeile 25, Spalte 0 }
- i2cdata[1] := 8;
- i2cdata[2] := speicher;
- i2cdata[3] := 25; i2cdata[4] := 0;
- i2cbusIO(SAA5246,^i2cdata,4);
- IF i2c_status<>0 THEN Exit;
- i2cbusIO(SAA5246,^status,-10);
- IF i2c_status<>0 THEN Exit;
- seite^.pg := (status[0] AND $F) + (status[1] AND $F) SHL 4
- + (status[8] AND $7) SHL 8;
- IF seite^.pg<$100 THEN seite^.pg := seite^.pg + $800;
- seite^.sp := (status[2] AND $F) + (status[3] AND $7) SHL 4
- + (status[4] AND $F) SHL 8 + (status[5] AND $3) SHL 12;
- seite^.cbits := (status[3] AND $08) SHL 1 { C4 }
- + (status[5] AND $0C) SHL 3 { C5, C6 }
- + (status[6] AND $0F) SHL 7 { C7, C8, C9, C10 }
- + (status[7] AND $0F) SHL 11 { C11, C12..C14 }
- IF ganz THEN BEGIN
- { Seite aus CCT lesen. Richtigen Speicher, Zeile 0, Spalte 0 adressieren: }
- i2cdata[1] := 8;
- i2cdata[2] := speicher;
- i2cdata[3] := 0; i2cdata[4] := 0;
- i2cbusIO(SAA5246,^i2cdata,4);
- IF i2c_status<>0 THEN Exit;
- { Seite einlesen: }
- i2cbusIO(SAA5246,^seite^.chars,-960);
- IF i2c_status<>0 THEN Exit;
- { in den freien Anfang der 1. Zeile die Unterseitennummer eintragen }
- seite^.chars[1] := Ord('(');
- seite^.chars[2] := Ord(hex[status[5] AND $3]);
- seite^.chars[3] := Ord(hex[status[4] AND $F]);
- seite^.chars[4] := Ord(hex[status[3] AND $7]);
- seite^.chars[5] := Ord(hex[status[2] AND $F]);
- seite^.chars[6] := Ord(')');
- seite^.chars[7] := Ord(' ');
- IF status[7] AND $01=0 THEN BEGIN { C11=0: Magazin-gemischte Übertragung, }
- seite^.chars[1] := Ord('<'); { Modus für den Benutzer erkennbar machen }
- seite^.chars[6] := Ord('>');
- END;
- { aus dem zur Anzeige aktivierten Seitenspeicher die Uhrzeit holen: }
- IF speicher<>aktspeicher THEN BEGIN
- gettime(aktspeicher,s);
- FOR i := 1 TO 8 DO
- seite^.chars[31+i] := Ord(s[i]);
- END;
- END;
- END;
-
- BEGIN { Initialisierungsteil }
- aktspeicher := 0;
- END.
-